Skip to content

Allow browsing skipped logfile content with chunk navigation#5326

Open
vetri15 wants to merge 3 commits intocodecentric:masterfrom
vetri15:master
Open

Allow browsing skipped logfile content with chunk navigation#5326
vetri15 wants to merge 3 commits intocodecentric:masterfrom
vetri15:master

Conversation

@vetri15
Copy link
Copy Markdown

@vetri15 vetri15 commented May 2, 2026

This PR implements the #4342 enhancement ,

other minor tweaks:

  • additionally The Buttons near the Follow mode toggle is changed from Plain SVG to font icon.
  • added i18n language support text for some missing text

vetri15 added 2 commits May 3, 2026 01:15
Add byte-range logfile chunk navigation for skipped content, with a compact follow/page up/page down toolbar that switches between live tailing and manual browsing. Also parse logfile window metadata, show skipped bytes for manual chunks, and add localized navigation labels.
@vetri15 vetri15 requested a review from a team as a code owner May 2, 2026 20:09
@cdprete
Copy link
Copy Markdown
Contributor

cdprete commented May 2, 2026

@SteKoe can we get this reviewed please?

Comment thread spring-boot-admin-server-ui/src/main/frontend/views/instances/logfile/index.vue Outdated
Comment thread spring-boot-admin-server-ui/src/main/frontend/views/instances/logfile/index.vue Outdated
@cdprete
Copy link
Copy Markdown
Contributor

cdprete commented May 3, 2026

Hi @vetri15.

I tested this a bit, by changing the servlet sample logging configuration to

logging:
  level:
    root: trace # even debug is fine

and I found the following bugs:

  • clicking the up arrow button twice indeed disables the following mode, which is in contrast the previous implementation.
  • if you try to navigate to the top, by continuously pressing the up button, it then starts to fail sometimes with
image
  • lines are broken

image

This would be difficult to fix. The only way I can think about is to always fetch:

-- the previous chunk and throw away everything that comes before the last new line. If it's the first chunk, nothing will be thrown away.
-- the next chunk and throw away everything that comes after the first new line. If it's the last chunk, nothing will be thrown away.
-- handle in a special way the first line of this new fetched chunk to prepend, if it's the previous chunk, respectively append, if it's the next chunk, it to the first, if it's the previous chunk, respectively last, if it's the next chunk, line of the current chunk.

  • going to the very top sometimes makes the view shrink and not always keep the full height (maybe it was a bug already existing but never visible since it was not possible to get chunks back)
image
  • if the follow mode is disabled and, later on, it gets reactivated, then the number of skipped bytes is wrong
image image

row.appendChild(col);
document.querySelector('.log-viewer > table')?.appendChild(row);
});
this.renderedLines = [...this.renderedLines, ...lines];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this imply we're keeping potentially the full log content in memory?
If it's so, that's not ideal at all.

Copy link
Copy Markdown
Author

@vetri15 vetri15 May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cdprete

I had the same thought. However, in the previous implementation, when navigating to the logfile view, it initially fetched around 300 KB, and while staying on the page it continued accumulating newly received log lines. The loaded content was only reset when the page was refreshed or when the user left the logfile view and opened it again.

Should I change this behavior so the logfile view always maintains a 300 KB sliding window instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I change this behavior so the logfile view always maintains a 300 KB sliding window instead?

Mmm I don't know.
@SteKoe @ulischulte your thoughts?

I want to avoid that the memory explodes with big log files.

However, in the previous implementation, when navigating to the logfile view, it initially fetched around 300 KB, and while staying on the page it continued accumulating newly received log lines.

But, if I'm not mistaken, before they were kept only in the dom as table rows and columns, while now we're also storming them as data.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cdprete

Yes, that makes sense. Keeping the log lines both in Vue state and in the rendered DOM does mean the content is effectively retained in two places.

However, directly appending rows to the DOM and then clearing the Vue state would make the DOM diverge from Vue’s source of truth, which seems risky and harder to maintain. Also, the expensive part is usually rendering and managing a large number of DOM nodes, so clearing only the JavaScript array would not fully solve the memory/performance concern.

I think the cleaner approach is to keep the rendered content itself bounded to 300kb sliding window limit.

Copy link
Copy Markdown
Contributor

@cdprete cdprete May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having such an hard limit would be risky, because it highly depends on how many lines can be rendered.
On large or high-density screens, it may not be enough.

Maybe the best would be to use something like https://github.com/hilongjw/vue-recyclerview or https://github.com/Akryum/vue-virtual-scroller (which is highly used in Android, for example, https://developer.android.com/develop/ui/views/layout/recyclerview) to reuse the existing DOM nodes rather than always creating and adding new ones.
This, together with proactively dropping a batch of non visible lines from the component state when a new chunk is fetched should keep the memory quite under control even with very big log files.

Copy link
Copy Markdown
Contributor

@cdprete cdprete May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall i implement this kind of solution

I can't say, because it would be a breaking change.
@SteKoe @ulischulte?

I think that, if you can show a notification to the user indicating that the content has been reloaded because the log file has been rotated, it's then safe enough.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay thanks @cdprete , I understand now.

  1. I will implement such that we are rendering only a small portion on the screen (~300kb) and a higher limit on the javascript (~2MB) so scrolling few chunks would be faster will leverage the vue libraries you provided, both will be constants so we can set them for what's apt in prod.

  2. I will show a notification after reloading logview table.

Copy link
Copy Markdown
Author

@vetri15 vetri15 May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cdprete

Regarding the table shrinking issue you mentioned, the current implementation always renders the exact chunk returned by the requested range, without overlapping it with the previously rendered chunk.

For example, if the current view shows lines 1–100 and the next chunk only contains lines 101–120 because we are near the start or end of the file, only those available lines are rendered.

I kept it this way so that each previous/next chunk action consistently moves to a new byte range without mixing content from the previous chunk. If we append or prepend part of the old chunk to keep the table height stable, the navigation would no longer represent a clean chunk progression.

So the trade-off is between:

  • preserving consistent chunk progression
  • preserving consistent visual table height

The current implementation favors consistent chunk progression.

if you prefer table consistency , please let me know , I will update the code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will leverage the vue libraries you provided, both will be constants so we can set them for what's apt in prod

They're not mine :)
Moreover, the recycle view pattern/idea is used a lot in Android, but I don't know if there are better options in Vue.
I let you and the team decide on it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you prefer table consistency , please let me know , I will update the code

If also the existing implementation presents the same behavior, then so be it.

if (this.atBottom) {
this.scrollToBottom();
if (shouldKeepAtBottom) {
this.$nextTick(() => this.scrollToBottom());
Copy link
Copy Markdown
Contributor

@cdprete cdprete May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to use $nextTick now?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need that $nextTick because the log rows are now rendered from renderedLines via Vue instead of being appended to the DOM manually. Updating renderedLines queues the DOM patch, so calling scrollToBottom() synchronously would read the previous scrollHeight. Waiting for the next tick ensures the new <tr> rows are in the DOM before we scroll.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, understood. Thanks.

@cdprete
Copy link
Copy Markdown
Contributor

cdprete commented May 5, 2026

@vetri15 by the way, let me know if I should test it again ;)

@vetri15
Copy link
Copy Markdown
Author

vetri15 commented May 5, 2026

@vetri15 by the way, let me know if I should test it again ;)

Thanks, @cdprete. I’m still working on a few edge cases, so it is taking a bit longer than expected. I’ll let you know once it’s ready for test.

@cdprete
Copy link
Copy Markdown
Contributor

cdprete commented May 5, 2026

@vetri15 by the way, let me know if I should test it again ;)

Thanks, @cdprete. I’m still working on a few edge cases, so it is taking a bit longer than expected. I’ll let you know once it’s ready for test.

No hurry ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants